#ifndef H_SRT_MATERIAL
#define H_SRT_MATERIAL

#include "srtColor.h"
#include "srtDynamicArray.h"

#define SRT_DEFAULT_AMBIENT_MATERIAL_COLOR 1.0, 1.0, 1.0, 1.0
#define SRT_DEFAULT_DIFFUSE_MATERIAL_COLOR 1.0, 1.0, 1.0, 1.0
#define SRT_DEFAULT_SPECULAR_MATERIAL_COLOR 0.2, 0.2, 0.2, 0.2
#define SRT_DEFAULT_SHININESS_MATERIAL_COEFFICIENT 5.0
#define SRT_DEFAULT_REFLECTIVITY_MATERIAL_COEFFICIENT 0.0
#define SRT_DEFAULT_TRANSMISSION_MATERIAL_COEFFICIENT 0.0
#define SRT_DEFAULT_REFRACTION_MATERIAL_COEFFICIENT 1.0

typedef struct {
	srtColor ambient, diffuse, specular;
	srtReal shininess, reflectivity, transmission, refraction;
} srtMaterial;

const srtMaterial SRT_DEFAULT_MATERIAL = {SRT_DEFAULT_AMBIENT_MATERIAL_COLOR, SRT_DEFAULT_DIFFUSE_MATERIAL_COLOR, SRT_DEFAULT_SPECULAR_MATERIAL_COLOR, SRT_DEFAULT_SHININESS_MATERIAL_COEFFICIENT, SRT_DEFAULT_REFLECTIVITY_MATERIAL_COEFFICIENT, SRT_DEFAULT_TRANSMISSION_MATERIAL_COEFFICIENT};

srtColor SRT_AMBIENT_MATERIAL_COLOR;
srtColor SRT_DIFFUSE_MATERIAL_COLOR;
srtColor SRT_SPECULAR_MATERIAL_COLOR;
srtReal  SRT_SHININESS_MATERIAL_COEFFICIENT;
srtReal  SRT_REFLECTIVITY_MATERIAL_COEFFICIENT;
srtReal  SRT_TRANSMISSION_MATERIAL_COEFFICIENT;
srtReal  SRT_REFRACTION_MATERIAL_COEFFICIENT;

int SRT_MATERIAL_DIRTY = 1;
srtDynamicArray *SRT_MATERIAL_ARRAY;

void srtMatAmbient4(srtReal r, srtReal g, srtReal b, srtReal a) {
	SRT_AMBIENT_MATERIAL_COLOR.r = srtClamp(r, 0.0, 1.0);
	SRT_AMBIENT_MATERIAL_COLOR.g = srtClamp(g, 0.0, 1.0);
	SRT_AMBIENT_MATERIAL_COLOR.b = srtClamp(b, 0.0, 1.0);
	SRT_AMBIENT_MATERIAL_COLOR.a = srtClamp(a, 0.0, 1.0);
	SRT_MATERIAL_DIRTY = 1;
}

void srtMatAmbient3(srtReal r, srtReal g, srtReal b) {
	srtMatAmbient4(r, g, b, 1.0);
}

void srtMatAmbient(const srtColor const *color) {
	srtMatAmbient4(color->r, color->g, color->b, color->a);
}

void srtMatDiffuse4(srtReal r, srtReal g, srtReal b, srtReal a) {
	SRT_DIFFUSE_MATERIAL_COLOR.r = srtClamp(r, 0.0, 1.0);
	SRT_DIFFUSE_MATERIAL_COLOR.g = srtClamp(g, 0.0, 1.0);
	SRT_DIFFUSE_MATERIAL_COLOR.b = srtClamp(b, 0.0, 1.0);
	SRT_DIFFUSE_MATERIAL_COLOR.a = srtClamp(a, 0.0, 1.0);
	SRT_MATERIAL_DIRTY = 1;
}

void srtMatSpecular4(srtReal r, srtReal g, srtReal b, srtReal a) {
	SRT_SPECULAR_MATERIAL_COLOR.r = srtClamp(r, 0.0, 1.0);
	SRT_SPECULAR_MATERIAL_COLOR.g = srtClamp(g, 0.0, 1.0);
	SRT_SPECULAR_MATERIAL_COLOR.b = srtClamp(b, 0.0, 1.0);
	SRT_SPECULAR_MATERIAL_COLOR.a = srtClamp(a, 0.0, 1.0);
	SRT_MATERIAL_DIRTY = 1;
}

void srtMatShininess(srtReal shininess) {
	SRT_SHININESS_MATERIAL_COEFFICIENT = shininess;
	SRT_MATERIAL_DIRTY = 1;
}

void srtMatReflectivity(srtReal reflectivity) {
	SRT_REFLECTIVITY_MATERIAL_COEFFICIENT = reflectivity;
	SRT_MATERIAL_DIRTY = 1;
}

void srtMatTransmission(srtReal transmission) {
	SRT_TRANSMISSION_MATERIAL_COEFFICIENT = transmission;
	SRT_MATERIAL_DIRTY = 1;
}

void srtMatRefraction(srtReal indexOfRefraction) {
	SRT_REFRACTION_MATERIAL_COEFFICIENT = indexOfRefraction;
	SRT_MATERIAL_DIRTY = 1;
}

/* return pointer and reset dirty flag */
srtMaterial *srtMatPtr(void) {
	if (SRT_MATERIAL_DIRTY) {
		srtMaterial mat = {SRT_AMBIENT_MATERIAL_COLOR, SRT_DIFFUSE_MATERIAL_COLOR, SRT_SPECULAR_MATERIAL_COLOR, SRT_SHININESS_MATERIAL_COEFFICIENT, SRT_REFLECTIVITY_MATERIAL_COEFFICIENT, SRT_TRANSMISSION_MATERIAL_COEFFICIENT};
		srtMaterial *matPtr = malloc(sizeof(srtMaterial));
		SRT_ASSERT(matPtr);
		*matPtr = mat;
		srtDynamicArray_PushBack(SRT_MATERIAL_ARRAY, matPtr);
		SRT_MATERIAL_DIRTY = 0;
	}
	return srtDynamicArray_Get(SRT_MATERIAL_ARRAY, SRT_MATERIAL_ARRAY->count - 1);
}

void srtMatReset(void) {
	SRT_AMBIENT_MATERIAL_COLOR.a = 1.0;
	SRT_AMBIENT_MATERIAL_COLOR.r = 1.0;
	SRT_AMBIENT_MATERIAL_COLOR.g = 1.0;
	SRT_AMBIENT_MATERIAL_COLOR.b = 1.0;
	
	SRT_DIFFUSE_MATERIAL_COLOR.a = 1.0;
	SRT_DIFFUSE_MATERIAL_COLOR.r = 1.0;
	SRT_DIFFUSE_MATERIAL_COLOR.g = 1.0;
	SRT_DIFFUSE_MATERIAL_COLOR.b = 1.0;
	
	SRT_SPECULAR_MATERIAL_COLOR.a = 0.5;
	SRT_SPECULAR_MATERIAL_COLOR.r = 0.5;
	SRT_SPECULAR_MATERIAL_COLOR.g = 0.5;
	SRT_SPECULAR_MATERIAL_COLOR.b = 0.5;
	
	SRT_SHININESS_MATERIAL_COEFFICIENT = SRT_DEFAULT_SHININESS_MATERIAL_COEFFICIENT;
	SRT_REFLECTIVITY_MATERIAL_COEFFICIENT = SRT_DEFAULT_REFLECTIVITY_MATERIAL_COEFFICIENT;
	SRT_TRANSMISSION_MATERIAL_COEFFICIENT = SRT_DEFAULT_TRANSMISSION_MATERIAL_COEFFICIENT;
	SRT_REFRACTION_MATERIAL_COEFFICIENT = SRT_DEFAULT_REFRACTION_MATERIAL_COEFFICIENT;
}

void srtColor4(srtReal r, srtReal g, srtReal b, srtReal a) {
	/* Clamped values */
	srtReal cr, cg, cb, ca;
	cr = srtClamp(r, 0.0, 1.0);
	cg = srtClamp(g, 0.0, 1.0);
	cb = srtClamp(b, 0.0, 1.0);
	ca = srtClamp(a, 0.0, 1.0);
	
	SRT_AMBIENT_MATERIAL_COLOR.a = ca;
	SRT_AMBIENT_MATERIAL_COLOR.r = cr;
	SRT_AMBIENT_MATERIAL_COLOR.g = cg;
	SRT_AMBIENT_MATERIAL_COLOR.b = cb;
	
	SRT_DIFFUSE_MATERIAL_COLOR.a = ca;
	SRT_DIFFUSE_MATERIAL_COLOR.r = cr;
	SRT_DIFFUSE_MATERIAL_COLOR.g = cg;
	SRT_DIFFUSE_MATERIAL_COLOR.b = cb;
	
	SRT_SPECULAR_MATERIAL_COLOR.a = 0.5;
	SRT_SPECULAR_MATERIAL_COLOR.r = 0.5;
	SRT_SPECULAR_MATERIAL_COLOR.g = 0.5;
	SRT_SPECULAR_MATERIAL_COLOR.b = 0.5;
	
	SRT_SHININESS_MATERIAL_COEFFICIENT = SRT_DEFAULT_SHININESS_MATERIAL_COEFFICIENT;
	SRT_REFLECTIVITY_MATERIAL_COEFFICIENT = SRT_DEFAULT_REFLECTIVITY_MATERIAL_COEFFICIENT;
	SRT_TRANSMISSION_MATERIAL_COEFFICIENT = SRT_DEFAULT_TRANSMISSION_MATERIAL_COEFFICIENT;
	SRT_REFRACTION_MATERIAL_COEFFICIENT = SRT_DEFAULT_REFRACTION_MATERIAL_COEFFICIENT;
	
	SRT_MATERIAL_DIRTY = 1;
}

void srtColor3(srtReal r, srtReal g, srtReal b) {
	srtColor4(r, g, b, 1.0);
}

void srtColorv(srtColor *color) {
	srtColor4(color->r, color->g, color->b, color->a);
}
#endif